/**
 * observe、defineReactive
 * set和del函数，用于在响应式对象上添加或删除属性
 * 实现数据的“响应式”更新。Vue通过这套系统追踪数据的依赖，
 * 并在数据变化时自动更新依赖于这些数据的视图。
 */
import Dep from './dep' // 依赖管理器，用于收集和触发依赖
import VNode from '../vdom/vnode' // 虚拟DOM节点
import { arrayMethods } from './array' // 数组方法重写，用于拦截数组操作
import {def,
  warn,
  hasOwn,
  isArray,
  hasProto,
  isPlainObject,
  isPrimitive,
  isUndef,
  isValidArrayIndex,
  isServerRendering,
  hasChanged,
  noop
} from '../util/index'
import { isReadonly,
   isRef, 
   TrackOpTypes, 
   TriggerOpTypes 
  } from '../../v3' // 引入Vue 3版本的响应式相关函数

// 获取重写后的数组方法名
const arrayKeys = Object.getOwnPropertyNames(arrayMethods)
// 用于标记初始值未定义
const NO_INITIAL_VALUE = {}

// 全局变量，控制是否应该观察数据
export let shouldObserve: boolean = true
// 切换观察状态
export function toggleObserving(value: boolean) {
  shouldObserve = value
}
// mockDep对象，用于非生产环境或SSR（服务器端渲染）时的依赖管理
const mockDep = {
  notify: noop,
  depend: noop,
  addSub: noop,
  removeSub: noop
} as Dep

// Observer类，用于观察数据对象或数组
export class Observer {
  dep: Dep
  vmCount: number 
  constructor(public value: any, public shallow = false, public mock = false) {
    // 初始化依赖管理器
    this.dep = mock ? mockDep : new Dep()
    this.vmCount = 0
    // 在被观察对象上标记Observer实例
    def(value, '__ob__', this)
    // 根据数据类型进行不同的处理
    if (isArray(value)) {
      // 对数组进行特殊处理，重写其原型方法或直接在数组上定义新方法
      if (!mock) {
        if (hasProto) {
          ;(value as any).__proto__ = arrayMethods
        } else {
          for (let i = 0, l = arrayKeys.length; i < l; i++) {
            const key = arrayKeys[i]
            def(value, key, arrayMethods[key])
          }
        }
      }
      // 递归观察数组元素
      if (!shallow) {this.observeArray(value)}
    } else {
      // 对普通对象，递归观察其属性
      const keys = Object.keys(value)
      for (let i = 0; i < keys.length; i++) {
        const key = keys[i]
        defineReactive(value, key, NO_INITIAL_VALUE, undefined, shallow, mock)
      }
    }
  }
  observeArray(value: any[]) {
    // 递归观察数组中的每个元素
    for (let i = 0, l = value.length; i < l; i++) {
      observe(value[i], false, this.mock)
    }
  }
}
// observe函数，用于创建Observer实例观察数据
export function observe(
  value: any,
  shallow?: boolean,
  ssrMockReactivity?: boolean
): Observer | void {
  // 检查数据是否已被观察
  if (value && hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
    // 数据已被观察
    return value.__ob__
  }
  // 判断是否应该观察该数据
  if (
    shouldObserve &&
    (ssrMockReactivity || !isServerRendering()) &&
    (isArray(value) || isPlainObject(value)) &&
    Object.isExtensible(value) &&
    !value.__v_skip /* ReactiveFlags.SKIP */ &&
    !isRef(value) &&
    !(value instanceof VNode)
  ) {
    //创建并返回新的Observer实例
    return new Observer(value, shallow, ssrMockReactivity)
  }
}
// defineReactive函数，用于定义响应式属性
export function defineReactive(
  obj: object,
  key: string,
  val?: any,
  customSetter?: Function | null,
  shallow?: boolean,
  mock?: boolean,
  observeEvenIfShallow = false
) {
  // 创建新的依赖管理器
  const dep = new Dep()
  // 获取属性描述符，检查属性是否可配置
  const property = Object.getOwnPropertyDescriptor(obj, key)
  if (property && property.configurable === false) {
    return
  }
   // 获取getter和setter
  const getter = property && property.get
  const setter = property && property.set
    // 如果没有setter但有getter，或者初始值为NO_INITIAL_VALUE，则获取当前值
  if ((!getter || setter) && (val === NO_INITIAL_VALUE || arguments.length === 2)
  ) {
    val = obj[key]
  }
  // 递归观察属性值
  let childOb = shallow ? val && val.__ob__ : observe(val, false, mock)
  // 使用Object.defineProperty定义响应式属性
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      const value = getter ? getter.call(obj) : val
      if (Dep.target) {
        if (__DEV__) {
          // 依赖收集
          dep.depend({
            target: obj,
            type: TrackOpTypes.GET,
            key
          })
        } else {
          dep.depend()
        }
        if (childOb) {
          childOb.dep.depend()
          if (isArray(value)) {
            dependArray(value)
          }
        }
      }
      return isRef(value) && !shallow ? value.value : value
    },
    set: function reactiveSetter(newVal) {
      const value = getter ? getter.call(obj) : val
      if (!hasChanged(value, newVal)) {
        return
      }
      if (__DEV__ && customSetter) {
        customSetter()
      }
      // 调用自定义setter或原生setter
      if (setter) {
        setter.call(obj, newVal)
      } else if (getter) {
        /// 对于只有getter没有setter的属性，直接返回
        return
      } else if (!shallow && isRef(value) && !isRef(newVal)) {
        value.value = newVal
        return
      } else {
        // 处理ref和普通值的更新
        val = newVal
      }
      // 更新依赖并触发通知
      childOb = shallow ? newVal && newVal.__ob__ : observe(newVal, false, mock)
      if (__DEV__) {
        dep.notify({
          type: TriggerOpTypes.SET,
          target: obj,
          key,
          newValue: newVal,
          oldValue: value
        })
      } else {
        dep.notify()
      }
    }
  })
  return dep
}
export function set<T>(array: T[], key: number, value: T): T
export function set<T>(object: object, key: string | number, value: T): T
// set和del函数，用于在响应式对象上添加或删除属性
export function set(
  target: any[] | Record<string, any>,
  key: any,
  val: any
): any {
  if (__DEV__ && (isUndef(target) || isPrimitive(target))) {
    warn(
      // 不能在未定义、null或原始值上设置响应属性
      `Cannot set reactive property on undefined, null, or primitive value: ${target}`
    )
  }
  // 判断是否为只读
  if (isReadonly(target)) {
    __DEV__ && warn(`Set operation on key "${key}" failed: target is readonly.`)
    return
  }
  const ob = (target as any).__ob__
  if (isArray(target) && isValidArrayIndex(key)) {
    target.length = Math.max(target.length, key)
    target.splice(key, 1, val)
    //当模拟SSR时，数组方法不会被劫持
    // when mocking for SSR, array methods are not hijacked
    if (ob && !ob.shallow && ob.mock) {
      observe(val, false, true)
    }
    return val
  }
  if (key in target && !(key in Object.prototype)) {
    target[key] = val
    return val
  }
  if ((target as any)._isVue || (ob && ob.vmCount)) {
    __DEV__ &&
      warn(
        //避免在运行时向Vue实例或它的根$data添加响应性属性——在data选项中预先声明。
        'Avoid adding reactive properties to a Vue instance or its root $data ' +
          'at runtime - declare it upfront in the data option.'
      )
    return val
  }
  if (!ob) {
    target[key] = val
    return val
  }
  defineReactive(ob.value, key, val, undefined, ob.shallow, ob.mock)
  // 通知所有订阅者更新
  if (__DEV__) {
    ob.dep.notify({
      type: TriggerOpTypes.ADD,
      target: target,
      key,
      newValue: val,
      oldValue: undefined
    })
  } else {
    ob.dep.notify()
  }
  return val
}
export function del<T>(array: T[], key: number): void
export function del(object: object, key: string | number): void
export function del(target: any[] | object, key: any) {
  if (__DEV__ && (isUndef(target) || isPrimitive(target))) {
    warn(
      `Cannot delete reactive property on undefined, null, or primitive value: ${target}`
    )
  }
  if (isArray(target) && isValidArrayIndex(key)) {
    target.splice(key, 1)
    return
  }
  const ob = (target as any).__ob__
  if ((target as any)._isVue || (ob && ob.vmCount)) {
    __DEV__ &&
      warn(
        'Avoid deleting properties on a Vue instance or its root $data ' +
          '- just set it to null.'
      )
    return
  }
  if (isReadonly(target)) {
    __DEV__ &&
      warn(`Delete operation on key "${key}" failed: target is readonly.`)
    return
  }
  if (!hasOwn(target, key)) {
    return
  }
  delete target[key]
  if (!ob) {
    return
  }
  if (__DEV__) {
    ob.dep.notify({
      type: TriggerOpTypes.DELETE,
      target: target,
      key
    })
  } else {
    ob.dep.notify()
  }
}
// 遍历数组，对每个元素进行依赖收集
function dependArray(value: Array<any>) {
  for (let e, i = 0, l = value.length; i < l; i++) {
    e = value[i]
    if (e && e.__ob__) {
      e.__ob__.dep.depend()
    }
    if (isArray(e)) {
      dependArray(e)
    }
  }
}
